package com.dliyun.db.migration.file;

import com.dliyun.db.migration.exception.DbMigrationException;
import org.springframework.core.io.Resource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.zip.CRC32;

public class ChecksumCalculator {

    private static final char BOM = '\ufeff';


    /**
     * Determine if this char is a UTF-8 Byte Order Mark
     *
     * @param c The char to check
     * @return Whether this char is a UTF-8 Byte Order Mark
     */
    private static boolean isBom(char c) {
        return c == BOM;
    }

    /**
     * Removes the UTF-8 Byte Order Mark from the start of a string if present.
     *
     * @param s The string
     * @return The string without a Byte Order Mark at the start
     */
    private static String filterBomFromString(String s) {
        if (s.isEmpty()) {
            return s;
        }

        if (isBom(s.charAt(0))) {
            return s.substring(1);
        }

        return s;
    }

    public static int calculate(Resource resource) {
        final CRC32 crc32 = new CRC32();

        BufferedReader bufferedReader = null;
        try {
            InputStream in = resource.getInputStream();
            InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);

            bufferedReader = new BufferedReader(isr, 4096);
            String line = bufferedReader.readLine();

            if (line != null) {
                line = filterBomFromString(line);
                do {
                    //noinspection Since15
                    crc32.update(line.getBytes(StandardCharsets.UTF_8));
                } while ((line = bufferedReader.readLine()) != null);
            }
        } catch (IOException e) {
            throw new DbMigrationException("Unable to calculate checksum of " + resource.getFilename() + "\r\n" + e.getMessage(), e);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (Exception e) {
                    // Ignore
                }
            }
        }

        return (int) crc32.getValue();
    }
}
